#include <nxos.h>

#define LSMAX_ARGS 32

enum {
	LSFLAG_DOT	= (1 << 0),
	LSFLAG_LONG	= (1 << 1),
};
NX_PRIVATE const char rwx[8][4] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" };

NX_PRIVATE void LsDetail(const char *path, NX_FileStatInfo *st)
{
    if(NX_FILE_IS_DIR(st->mode))
    {
        NX_Printf("d");
    }
    if(NX_FILE_IS_REG(st->mode))
    {
        NX_Printf("-");
    }

    NX_Printf("%s", rwx[(st->mode & NX_FILE_MODE_MASK) >> 6]);

    NX_Time tm;
    NX_TimeStampToTime(st->mtime, &tm);

    NX_Printf(" %8ld %04d/%02d/%02d %02d:%02d:%02d %s\r\n", 
        st->size, tm.year + NX_TIME_YEAR_BASE, tm.month + 1,
        tm.day, tm.hour, tm.minute, tm.second, path);
}

NX_PRIVATE void DoLs(const char * path, int flag)
{
    NX_FileStatInfo st;
	NX_Dirent dir;
	char buf[NX_FILE_MAX_PATH];
	int fd;

	if(NX_FileGetStatFromPath(path, &st) != NX_EOK)
	{
		NX_Printf("ls: cannot access %s: No such file or directory\r\n", path);
		return;
	}

    if(NX_FILE_IS_DIR(st.mode)) /* dir */
	{
        if((fd = NX_DirOpen(path)) >= 0)
		{
			while(NX_DirRead(fd, &dir) == NX_EOK)
			{
				if(!(flag & LSFLAG_DOT) && dir.name && (dir.name[0] == '.')) /* skip `.` and `..` */
                {
					continue;
                }
                NX_StrPrintfN(buf, sizeof(buf), "%s/%s", path, dir.name);

                if(NX_FileGetStatFromPath(buf, &st) != NX_EOK)
                {
                    NX_Printf("ls: cannot access %s: No such file or directory\r\n", path);
                    continue;
                }

				if (flag & LSFLAG_LONG)
                {
                    LsDetail(dir.name, &st);
                }
                else
                {
                    NX_Printf("%s ", dir.name);
                }
			}
			NX_DirClose(fd);
		}
        
        if (!(flag & LSFLAG_LONG))
        {
            NX_Printf("\r\n");
        }
    }
    else
    {
        if (flag & LSFLAG_LONG)
        {
            LsDetail(path, &st);
        }
        else
        {
            NX_Printf("%s\r\n", path);
        }
    }
}

NX_Error PowerBoxBuiltinLs(int argc, char *argv[], char * env)
{
    char *v[LSMAX_ARGS];
    int flag = 0;
	int c = 0;
	int i;

	for(i = 1; i < argc; i++)
	{
		if (NX_StrCmp(argv[i], "-l") == 0)
        {
			flag |= LSFLAG_LONG;
        }
		else if (NX_StrCmp(argv[i], "-a") == 0)
        {
			flag |= LSFLAG_DOT;
        }
        else if (NX_StrCmp(argv[i], "-la") == 0 || NX_StrCmp(argv[i], "-al") == 0)
        {
			flag |= LSFLAG_DOT | LSFLAG_LONG;
        }
        else if (NX_StrCmp(argv[i], "-h") == 0)
        {
			NX_Printf("usage:\r\n    ls [-l] [-a] [FILE]...\r\n");
            return NX_EOK;
        }
		else
        {
			v[c++] = argv[i];
        }
	}

	if(c == 0)
    {
		v[c++] = ".";
    }

	for(i = 0; i < c; i++)
	{
		DoLs(v[i], flag);
	}

    return NX_EOK;
}
